<template>
  <div class="main-screen">
    <header-bar></header-bar>
    <content-bar></content-bar>
    <footer-bar></footer-bar>
    <resize-observer @notify="handleResize"/>
    <div v-show="false">
      <webview ref="printWebview" :src="receiptUrl" nodeintegration/>
    </div>
  </div>
</template>

<script>
import {mapGetters} from 'vuex'
import HeaderBar from '@/components/layout/HeaderBar'
import FooterBar from '@/components/layout/FooterBar'
import ContentBar from '@/components/layout/ContentBar'
import {latestShift} from '@/api/user'
import {getStockList} from '@/api/store'
import {ENV, PAY_WAY_NAME_MAP, POS_SERVER_URL} from '@/utils/common'
import {text2audio} from '@/utils/text2audio'
import {
  getCardRechargeReceiptText,
  getCommodityReceiptText,
  getCommodityRefundReceiptText,
  getFuelReceiptText,
  getFuelRefundReceiptText
} from '@/utils/receipt'
import {isCardReaderReady} from '@/utils/cardreader'
import {getCardInfoByUid} from '@/api/card'
import QRCode from 'qrcode'
import printer from 'pdf-to-printer'
import moment from 'moment'

const {ipcRenderer} = require('electron')

export default {
  name: 'MainScreen',
  components: {
    HeaderBar,
    FooterBar,
    ContentBar
  },
  data () {
    return {
      webSocket: null,
      lockReconnect: false,
      timeout: 15 * 1000, // 30秒一次心跳
      heartBeat: null,
      stockListInterval: null, // 获取商品列表定时器
      voiceBroadcastInterval: null, // 语音播报定时器
      receiptPrintInterval: null, // 小票打印定时器
      checkUpdateInterval: null, // 检查更新定时器
      getShiftInfoInterval: null, // 获取班次信息定时器
      printingReceipt: false, // 小票打印中
      receiptUrl: '',
      invoicePrintInterval: null // 发票打印定时器
    }
  },
  computed: {
    ...mapGetters([
      'stationId',
      'token',
      'operator',
      'voiceList',
      'receiptList',
      'receiptPrinter',
      'updateMsg',
      'mpPayReceiptOn',
      'mpRechargeReceiptOn',
      'pcRechargeReceiptOn',
      'localPayReceiptOn',
      'gunAmountVoiceLimit',
      'onlineReceiptOn',
      'userInfo',
      'invoiceList',
      'invoicePrinter',
      'stationName',
      'shiftName',
      'wxServerUrl',
      'invoicePrintTarget'
    ])
  },
  created () {
    ipcRenderer.removeAllListeners('invoice-downloaded')
    ipcRenderer.on('invoice-downloaded', (event, path) => {
      console.log('invoice-downloaded')
      console.log(path)
      if (this.invoicePrinter) {
        printer.print(path, {printer: this.invoicePrinter}).then(res => {
          console.log(res)
          console.log('print pdf success!', path)
        })
      }
    })
  },
  mounted () {
    this.receiptUrl = process.env.NODE_ENV === 'development' ? `http://localhost:9080/static/print/receipt.html` : `file://${__dirname}/../../../dist/electron/static/print/receipt.html`
    this.initWebSocket()
    this.$store.dispatch('setContentHeight', document.body.clientHeight - 90)
    this.stockListInterval = setInterval(() => this.getCommodityList(), 1000 * 60 * 5)
    this.voiceBroadcastInterval = setInterval(() => this.voiceBroadcast(), 3000)
    this.receiptPrintInterval = setInterval(() => this.receiptPrint(), 1000)
    this.invoicePrintInterval = setInterval(() => this.doInvoicePrint(), 3000)
    this.getCommodityList()
    this.initReceiptPrintListener()
    this.checkUpdateInterval = setInterval(() => this.checkForUpdate(), 1000 * 60 * 10)
    this.checkForUpdate()
    this.getShiftInfoInterval = setInterval(() => this.getLatestShiftInfo(), 1000 * 60 * 10)
    this.getLatestShiftInfo()
    this.$store.dispatch('setSecondScreenImageList', this.userInfo.imageList || [])
    // 监听更新返回消息
    ipcRenderer.on('message', (event, text) => {
      this.$store.dispatch('setUpdateMsg', text)
      console.log(text)
      if (text === '重启程序更新') {
        // 弹出提示是否关闭程序并执行更新
        this.$confirm('是否关闭程序执行程序更新', '版本更新提示', {type: 'warning'}).then(() => {
          this.$store.dispatch('setUpdateMsg', '')
          ipcRenderer.send('exit-and-update')
        })
      }
    })
  },
  methods: {
    initWebSocket () {
      var url = POS_SERVER_URL.replace('http', 'ws') + '/api/websocket?token=' + this.token + '&stationId=' + this.stationId + '&operator=' + this.operator
      this.webSocket = new WebSocket(url)
      this.webSocket.onopen = this.webSocketOnOpen
      this.webSocket.onclose = this.webSocketOnClose
      this.webSocket.onerror = this.webSocketOnError
      this.webSocket.onmessage = this.webSocketOnMessage
      this.startHeartBeat()
    },
    // webSocket建立连接
    webSocketOnOpen () {
      console.log('onopen')
      this.webSocket.send('heartbeat')
      this.webSocket.send('init')
      this.webSocket.send('saleList')
      this.$store.dispatch('posOnline')
    },
    // webSocket关闭连接
    webSocketOnClose () {
      console.log('onclose')
      this.$store.dispatch('posOffline')
      this.startHeartBeat()
    },
    // webSocket出错
    webSocketOnError (err) {
      console.log('onerror')
      console.log(err)
      this.$store.dispatch('posOffline')
      this.startHeartBeat()
    },
    // webSocket信息接收
    webSocketOnMessage (event) {
      let data = JSON.parse(event.data)
      this.$store.dispatch('posOnline')
      if (data && data.type === 'heartbeat') {
        // 心跳重置
        this.resetHeartBeat()
      } else {
        if (data.gunList) {
          console.log('收到-油枪列表')
          var gunList = JSON.parse(data.gunList)
          // console.log(gunList)
          this.$store.dispatch('setGunList', gunList)
        }
        if (data.fuelList) {
          console.log('收到-油品列表')
          var fuelList = JSON.parse(data.fuelList)
          // console.log(fuelList)
          this.$store.dispatch('setFuelList', fuelList)
        }
        if (data.toSettleList) {
          console.log('收到-待结算列表')
          var toSettleList = JSON.parse(data.toSettleList)
          // console.log(toSettleList)
          this.$store.dispatch('setToSettleList', toSettleList)
        }
        if (data.statusList) {
          console.log('收到-加油状态')
          var statusList = JSON.parse(data.statusList)
          // console.log(statusList)
          this.$store.dispatch('setGunStatusList', statusList)
        }
        if (data.saleFuelList) {
          console.log('收到-加油消费记录列表')
          var saleFuelList = JSON.parse(data.saleFuelList)
          // console.log(saleFuelList.length)
          this.$store.dispatch('setSaleFuelList', saleFuelList)
        }
        if (data.saleCommodityList) {
          console.log('收到-非油消费记录列表')
          var saleCommodityList = JSON.parse(data.saleCommodityList)
          // console.log(saleCommodityList.length)
          this.$store.dispatch('setSaleCommodityList', saleCommodityList)
        }
        if (data.saleFuelRecord) {
          console.log('收到-单条加油消费记录')
          var saleFuelRecord = JSON.parse(data.saleFuelRecord)
          console.log(saleFuelRecord)
          this.$store.dispatch('addSaleFuelRecord', saleFuelRecord)
          if (saleFuelRecord.paymentType !== 'unpaid') {
            this.filterPrintFuelReceipt(saleFuelRecord)
          }
        }
        if (data.saleCommodityRecord) {
          console.log('收到-单条非油消费记录')
          var saleCommodityRecord = JSON.parse(data.saleCommodityRecord)
          // console.log(saleCommodityRecord)
          this.$store.dispatch('addSaleCommodityRecord', saleCommodityRecord)
          this.filterPrintCommodityReceipt(saleCommodityRecord)
        }
        if (data.fuelRefundRecord) {
          console.log('收到-油品退款记录')
          var fuelRefundRecord = JSON.parse(data.fuelRefundRecord)
          this.$store.dispatch('updateSaleFuelRefundStatus', fuelRefundRecord)

          if (fuelRefundRecord.paymentType !== 'unpaid') {
            // 退款小票只打印本机操作的记录
            this.filterPrintRefundReceipt(fuelRefundRecord)
          }
        }
        if (data.storeRefundRecord) {
          console.log('收到-便利店退款记录')
          var storeRefundRecord = JSON.parse(data.storeRefundRecord)
          console.log(storeRefundRecord)
          // 刷新本地记录的支付状态
          this.$store.dispatch('updateSaleCommodityRefundStatus', storeRefundRecord)
          // 退款小票只打印本机操作的记录
          if (storeRefundRecord.salesman === this.operator) {
            this.$store.dispatch('addToReceiptList', getCommodityRefundReceiptText(storeRefundRecord))
          }
        }
        if (data.invoiceRecord) {
          console.log('收到-发票打印记录请求')
          var invoiceRecord = JSON.parse(data.invoiceRecord)
          this.filterPrintInvoice(invoiceRecord)
        }
        if (data.rechargeRecord) {
          console.log('收到-打印充值小票请求')
          var rechargeRecord = JSON.parse(data.rechargeRecord)
          this.printRechargeReceipt(rechargeRecord)
        }
        if (data.shiftRecord) {
          console.log('收到-交班操作记录')
          if (this.invoicePrintTarget !== 'android') {
            // 执行退出操作
            this.$store.dispatch('userLogout')
            this.$router.push('/login')
          } else {
            this.$message.warning('已经交班了！')
            this.$store.dispatch('clearReceiptAndVoiceList')
            this.$store.dispatch('clearPendingOrderList')
            this.$store.dispatch('setSaleFuelList', [])
            this.$store.dispatch('setSaleCommodityList', [])
          }
        }
      }
    },
    // 重新连接
    reconnect () {
      console.log('重新连接')
      if (this.lockReconnect) {
        return false
      }
      this.lockReconnect = true
      this.initWebSocket()
      this.lockReconnect = false
    },
    startHeartBeat () {
      console.log('重置并启动心跳')
      this.heartBeat && clearTimeout(this.heartBeat)
      this.heartBeat = setTimeout(() => {
        // 发送一个心跳，后端收到后返回一个心跳消息
        if (this.webSocket && this.webSocket.readyState === 1) {
          console.log('主动发送心跳')
          this.webSocket.send('heartbeat')
        } else {
          this.reconnect()
        }
      }, this.timeout)
    },
    resetHeartBeat () {
      clearTimeout(this.heartBeat)
      // 重启心跳
      this.startHeartBeat()
    },
    handleResize ({width, height}) {
      this.$store.dispatch('setContentHeight', height - 90)
    },
    // 获取商品列表
    getCommodityList () {
      getStockList(this.stationId).then(res => {
        console.log(res)
        this.$store.dispatch('setStockList', res.data)
      })
      this.$store.dispatch('setSecondScreenImageList', this.userInfo.imageList || [])
    },
    // 链接失败时直接登出会员
    userLogout () {
      if (this.$route.path !== '/secondary') {
        this.$store.dispatch('userLogout')
        this.$store.dispatch('clearReceiptAndVoiceList')
        this.$store.dispatch('clearPendingOrderList')
        this.$store.dispatch('setSaleFuelList', [])
        this.$store.dispatch('setSaleCommodityList', [])
        this.$store.dispatch('setFilterGun', '')
        this.$store.dispatch('setFilterPayType', '')
      }
    },
    // 支付成功语音播报
    voiceBroadcast () {
      // console.log('voiceBroadcast')
      // 从待播报队列中取出第一条记录
      if (this.voiceList.length > 0) {
        // console.log(this.voiceList[0])
        var text = this.voiceList[0].gunNo + '号枪 ' + this.voiceList[0].paymentTypeName + ' ' + this.voiceList[0].fuelAmount + '元'
        text2audio(text)
        this.$store.dispatch('popVoiceList')
      }
    },
    // 小票打印
    receiptPrint () {
      // 从打印队列中取出第一条
      if (this.receiptList.length > 0) {
        console.log('准备打印')
        console.log(this.receiptList[0])
        this.$refs.printWebview.send('webview-print-render', this.receiptList[0])
      }
    },
    initReceiptPrintListener () {
      const webview = this.$refs.printWebview
      webview.addEventListener('dom-ready', () => {
        // console.log('webview dom ready')
        // dom-ready---webview加载完成
        // webview.openDevTools() // 这个方法可以打开print.html的控制台
      })
      webview.addEventListener('ipc-message', event => {
        if (event.channel === 'webview-print-do') {
          webview.print({
            silent: true,
            printBackground: true,
            deviceName: this.receiptPrinter
          }).then(() => {
            console.log('print success')
            this.$store.dispatch('popReceiptList')
          })
        }
      })
    },
    // 发票打印
    doInvoicePrint () {
      // 从打印队列中取出第一条
      if (this.invoiceList.length > 0) {
        console.log(this.invoiceList[0])
        // 触发PDF下载操作
        ipcRenderer.send('download-invoice', this.invoiceList[0])
        // 队列中移除该记录
        this.$store.dispatch('popInvoiceList')
      }
    },
    // 检查更新
    checkForUpdate () {
      console.log(ENV)
      // 只有客户端处于打包状态且环境配置是正式环境才执行
      if (process.env.NODE_ENV === 'production' && ENV === 'prod' && this.updateMsg !== '重启程序更新') {
        ipcRenderer.send('checkForUpdate') // 正式库才执行发送检查更新指令
      }
    },
    getLatestShiftInfo () {
      // 获取最新班次信息
      latestShift(this.stationId).then(res => {
        console.log(res)
        this.$store.dispatch('setShiftInfo', res.data)
      }).catch(err => {
        console.log(err)
      })
    },
    // 判断是否需要打印小票
    filterPrintFuelReceipt (saleFuelRecord) {
      // 如果是预付款勾兑推送过来的记录，则不语音播报和打印小票
      if (!(saleFuelRecord.remark && saleFuelRecord.remark.indexOf('-A') > -1)) {
        this.filterPlayVoice(saleFuelRecord)
        if (this.mpPayReceiptOn && saleFuelRecord.paymentType === 'mpPay') {
          // 是否打印点付小票
          this.$store.dispatch('addToReceiptList', getFuelReceiptText(saleFuelRecord))
        } else if (this.localPayReceiptOn && saleFuelRecord.operator === this.operator) {
          // 是否打印本机结算的小票
          // 如果是储值卡，则先获取储值卡的实时余额
          if (saleFuelRecord.cardUid) {
            getCardInfoByUid(saleFuelRecord.cardUid).then(res => {
              console.log(res)
              // 把卡的余额信息写如到记录中
              saleFuelRecord.balance = res.data.balance
              saleFuelRecord.cardNo = res.data.cardNo
              saleFuelRecord.cardName = res.data.cardName
              saleFuelRecord.username = res.data.username
              saleFuelRecord.carNumber = res.data.carNumber
              saleFuelRecord.invoiceType = res.data.invoiceType
              const receiptText = getFuelReceiptText(saleFuelRecord)
              this.$store.dispatch('addToReceiptList', receiptText)
              this.$store.dispatch('addToReceiptList', receiptText)
            }).catch(err => {
              console.log(err)
              this.$store.dispatch('addToReceiptList', getFuelReceiptText(saleFuelRecord))
            })
          } else {
            this.$store.dispatch('addToReceiptList', getFuelReceiptText(saleFuelRecord))
          }
        } else if (this.mpPayReceiptOn && saleFuelRecord.paymentType === 'oilcard' && !isNaN(saleFuelRecord.operator)) {
          // 点付油卡
          getCardInfoByUid(saleFuelRecord.cardUid).then(res => {
            console.log(res)
            // 把卡的余额信息写如到记录中
            saleFuelRecord.balance = res.data.balance
            saleFuelRecord.cardNo = res.data.cardNo
            saleFuelRecord.invoiceType = res.data.invoiceType
            this.$store.dispatch('addToReceiptList', getFuelReceiptText(saleFuelRecord))
          }).catch(err => {
            console.log(err)
            this.$store.dispatch('addToReceiptList', getFuelReceiptText(saleFuelRecord))
          })
        } else if (saleFuelRecord.operator !== this.operator) {
          console.log('非本机结算记录，不打印小票！')
        }
      }
    },
    // 判断是线上小票还是线下小票
    printRechargeReceipt (rechargeRecord) {
      console.log('====rechargeRecord====')
      console.log(rechargeRecord)
      var receipt = {
        stationName: this.stationName,
        cardNo: rechargeRecord.cardNo,
        paymentTypeName: PAY_WAY_NAME_MAP[rechargeRecord.payType],
        paymentChannel: '',
        amount: rechargeRecord.amount,
        balance: rechargeRecord.balanceAfter,
        operator: rechargeRecord.operator,
        shiftName: this.shiftName,
        rechargeDate: moment(new Date(rechargeRecord.rechargeDate)).format('YYYY-MM-DD HH:mm:ss')
      }
      // 如果是线上充值，操作员的值为String的null   ！！！！
      if (rechargeRecord.operator === 'null' || !isNaN(rechargeRecord.operator)) {
        receipt.paymentChannel = '线上充值'
        if (this.mpRechargeReceiptOn) {
          // 将小票操作员更改为当前登录使用的收银员，不显示null
          receipt.operator = this.operator
          this.$store.dispatch('addToReceiptList', getCardRechargeReceiptText(receipt))
        }
      } else if (rechargeRecord.rechargeScene === 'pcRecharge' || rechargeRecord.rechargeScene === 'reversalRecharge') {
        receipt.paymentChannel = rechargeRecord.rechargeScene === 'pcRecharge' ? '后台充值' : '冲正充值'
        if (this.pcRechargeReceiptOn) {
          this.$store.dispatch('addToReceiptList', getCardRechargeReceiptText(receipt))
        }
      } else {
        receipt.paymentChannel = '线下充值'
        // 仅打印当前设备的充值记录
        if (receipt.operator === this.operator) {
          this.$store.dispatch('addToReceiptList', getCardRechargeReceiptText(receipt))
        }
      }
    },

    // 判断是否需要打印退款小票
    filterPrintRefundReceipt (fuelRefundRecord) {
      if (fuelRefundRecord.operator === this.operator) {
        if (fuelRefundRecord.cardUid) {
          getCardInfoByUid(fuelRefundRecord.cardUid).then(res => {
            console.log(res)
            // 把卡的余额信息写如到记录中
            fuelRefundRecord.balance = res.data.balance
            fuelRefundRecord.cardNo = res.data.cardNo
            this.$store.dispatch('addToReceiptList', getFuelRefundReceiptText(fuelRefundRecord))
          }).catch(err => {
            console.log(err)
            this.$store.dispatch('addToReceiptList', getFuelRefundReceiptText(fuelRefundRecord))
          })
        } else {
          this.$store.dispatch('addToReceiptList', getFuelRefundReceiptText(fuelRefundRecord))
        }
      }
    },

    // 判断是否要语音播报
    filterPlayVoice (saleFuelRecord) {
      // 如果符合语音播报限制列表的枪号和金额则不播报语音
      var tmp = this.gunAmountVoiceLimit.filter(item => item.gunNo + '' === saleFuelRecord.gunNo + '')
      if (tmp.length > 0 && tmp[0].amount > saleFuelRecord.fuelAmount) {
        console.log(saleFuelRecord.gunNo + '号枪消费' + saleFuelRecord.fuelAmount + '元不播报语音')
        return false
      }
      this.$store.dispatch('addToVoiceList', saleFuelRecord)
    },

    filterPrintCommodityReceipt (saleCommodityRecord) {
      // 只打印本机结算的非油消费记录
      if (saleCommodityRecord.salesman === this.operator) {
        this.$store.dispatch('addToReceiptList', getCommodityReceiptText(saleCommodityRecord))
      } else if (this.onlineReceiptOn && saleCommodityRecord.status === 2 && saleCommodityRecord.payStatus === 1) {
        // 如果开启了点付小票打印，则把线上购买的便利店小票也打印出来
        console.log('线上购买需要打印二维码小票')
        QRCode.toDataURL(saleCommodityRecord.uid)
          .then(url => {
            console.log(url)
            saleCommodityRecord.qrcode = url
            this.$store.dispatch('addToReceiptList', getCommodityReceiptText(saleCommodityRecord))
          })
          .catch(err => {
            console.error(err)
          })
      } else if (saleCommodityRecord.payType === 'mpPay' && this.onlineReceiptOn) {
        console.log('点付便利店商品购买打印')
        this.$store.dispatch('addToReceiptList', getCommodityReceiptText(saleCommodityRecord))
      }
    },

    // 检测读卡器是否连接正常
    checkCardReader () {
      if (isCardReaderReady()) {
        this.$store.dispatch('cardReaderOnline')
      } else {
        this.$store.dispatch('cardReaderOffline')
      }
    },

    filterPrintInvoice (invoiceRecord) {
      console.log(invoiceRecord)
      if (invoiceRecord.invoiceUrl && this.invoicePrintTarget) {
        // 根据当前设置判断该笔记录是否应该进行打印操作
        // 如果打印发票对象为自助结算机，则操作人信息字段应该包含"android"属性
        if (this.invoicePrintTarget === 'android' && invoiceRecord.orderOperator && invoiceRecord.orderOperator.indexOf('android') > -1) {
          console.log('自助结算机结算发票')
          this.$store.dispatch('addToInvoiceList', invoiceRecord.invoiceUrl)
        }
        if (this.invoicePrintTarget !== 'android' &&
            (!invoiceRecord.orderOperator || (invoiceRecord.orderOperator && invoiceRecord.orderOperator.indexOf('android') === -1))) {
          console.log('非自助结算机结算发票')
          this.$store.dispatch('addToInvoiceList', invoiceRecord.invoiceUrl)
        }
      }
    }
  },
  beforeDestroy () {
    console.log('beforeDestroy')
    this.heartBeat && clearTimeout(this.heartBeat)
    // 关闭webSocket
    if (this.webSocket) {
      this.webSocket.close()
    }
    this.lockReconnect = true
    this.userLogout()
    // 清除定时器
    window.clearInterval(this.stockListInterval)
    window.clearInterval(this.voiceBroadcastInterval)
    window.clearInterval(this.receiptPrintInterval)
    window.clearInterval(this.checkUpdateInterval)
    window.clearInterval(this.getShiftInfoInterval)
    window.clearInterval(this.invoicePrintInterval)
  }
}
</script>
<style scoped>
.main-screen {
  width: 100%;
  height: 100%;
}

.main-content {
  position: absolute;
  top: 60px;
  width: 100%;
  height: calc(100% - 91px);
  bottom: 30px;
  background: #f0f0f0;
}
</style>
